;//
;// handler.asm
;// Usage: Interrupt handler
;// Create Date: 2007-09-03
;// Author: MaJiuyue
;//
%include "sconst.inc"

global divide_error
global single_step_exception
global nmi
global breakpoint_exception
global overflow
global bounds_check
global inval_opcode
global copr_not_available
global double_fault
global copr_seg_overrun
global inval_tss
global segment_not_present
global stack_exception
global general_protection
global page_fault
global copr_error
global hwint00
global hwint01
global hwint02
global hwint03
global hwint04
global hwint05
global hwint06
global hwint07
global hwint08
global hwint09
global hwint10
global hwint11
global hwint12
global hwint13
global hwint14
global hwint15
global _syscall

[section .intr]
divide_error:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 0			; vector_no	= 0
	jmp	exception_common_stub

single_step_exception:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 1			; vector_no	= 1
	jmp	exception_common_stub

nmi:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 2			; vector_no	= 2
	jmp	exception_common_stub

breakpoint_exception:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 3			; vector_no	= 3
	jmp	exception_common_stub

overflow:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 4			; vector_no	= 4
	jmp	exception_common_stub

bounds_check:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 5			; vector_no	= 5
	jmp	exception_common_stub

inval_opcode:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 6			; vector_no	= 6
	jmp	exception_common_stub

copr_not_available:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 7			; vector_no	= 7
	jmp	exception_common_stub

double_fault:
	cli
	push dword 8			; vector_no	= 8
	jmp	exception_common_stub

copr_seg_overrun:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 9			; vector_no	= 9
	jmp	exception_common_stub

inval_tss:
	cli
	push dword 10			; vector_no	= A
	jmp	exception_common_stub

segment_not_present:
	cli
	push dword 11			; vector_no	= B
	jmp	exception_common_stub

stack_exception:
	cli
	push dword 12			; vector_no	= C
	jmp	exception_common_stub

general_protection:
	cli
	push dword 13			; vector_no	= D
	jmp	exception_common_stub

page_fault:
	cli
	push dword 14			; vector_no	= E
	jmp exception_common_stub

copr_error:
	cli
	push dword 0xFFFFFFFF		; no err code
	push dword 16			; vector_no	= 10h
	jmp	exception_common_stub

extern exception_handler	
exception_common_stub:
	xchg [ss:esp], eax	; vec_no <==> eax
	push ecx
	push edx
	push ebx
	push esp
	push ebp
	push esi
	push edi
	push ds
	push es
	push fs
	push gs

	mov cx, ss
	mov ds, cx
	mov es, cx
	mov fs, cx
	mov gs, cx

	; save `regs' address
	mov esi, esp

	; switch stack
	and esp, 0xFFFFE000
	add esp, 0x2000

	; call exception handler
	push esi				; regs
	push dword [esi+RETADR-P_STACKBASE]	; err_code
	push eax				; vec_no
	call exception_handler
	add esp, 12 

	; switch stack back to `regs'
	sub esp, 0x1ffc
	pop gs
	pop fs
	pop es
	pop ds
	popad
	add esp, 4
	iretd


extern irq_handler
%macro	hwint_master	1
	;Save status
	call save

	; Disable IRQ#
	in	al, PIC_M_CTLMASK
	or	al, (1 << %1)
	out	PIC_M_CTLMASK, al
	;Send EOI
	mov	al, EOI
	out	PIC_M_CTL, al

	push esi
	push dword %1
	call irq_handler
	add esp, 8

	;inc byte [0xb8000 + 3200]

	; k_reenter--
	dec dword [k_reenter]

	sub esp, 0x1ffc
	;Restore status
	pop	gs
	pop	fs
	pop	es
	pop	ds
	popad
	add esp, 4
	iretd
%endmacro

ALIGN	16
; Interrupt routine for irq 0 (the clock).
hwint00:
	hwint_master 0
	
ALIGN	16
	; Interrupt routine for irq 1 (keyboard)
hwint01:
	hwint_master 1

ALIGN	16
; Interrupt routine for irq 2 (cascade!)
hwint02:
	hwint_master 2

ALIGN	16
; Interrupt routine for irq 3 (second serial)
hwint03:
	hwint_master 3

ALIGN	16
; Interrupt routine for irq 4 (first serial)
hwint04:
	hwint_master 4

ALIGN	16
; Interrupt routine for irq 5 (XT winchester)
hwint05:
	hwint_master 5

ALIGN	16
; Interrupt routine for irq 6 (floppy)
hwint06:
	hwint_master 6

ALIGN	16
; Interrupt routine for irq 7 (printer)
hwint07:
	hwint_master 7


%macro	hwint_slave	1
	;Save status
	call save

	; Disable IRQ#
	in	al, PIC_S_CTLMASK
	or	al, (1 << (%1)-8)
	out	PIC_S_CTLMASK, al
	;Send EOI
	mov	al, EOI
	out	PIC_S_CTL, al
	out	PIC_M_CTL, al

	push esi
	push dword %1
	call irq_handler
	add esp, 8

	; k_reenter--
	dec dword [k_reenter]

	sub esp, 0x1ffc
	;Restore status
	pop	gs
	pop	fs
	pop	es
	pop	ds
	popad
	add esp, 4
	iretd
%endmacro

hwint08:		; Interrupt routine for irq 8 (realtime clock).
	hwint_slave		8

hwint09:		; Interrupt routine for irq 9 (irq 2 redirected)
	hwint_slave		9

ALIGN	16
hwint10:		; Interrupt routine for irq 10
	hwint_slave		10

ALIGN	16
hwint11:		; Interrupt routine for irq 11
	hwint_slave		11

ALIGN	16
hwint12:		; Interrupt routine for irq 12
	hwint_slave		12

ALIGN	16
hwint13:		; Interrupt routine for irq 13 (FPU exception)
	hwint_slave		13

ALIGN	16
hwint14:		; Interrupt routine for irq 14 (AT winchester)
	hwint_slave		14

ALIGN	16
hwint15:		; Interrupt routine for irq 15
	hwint_slave		15


;------------------------------SAVE----------------------------
global k_reenter
k_reenter	dd		0
save:
	pushad
	push ds
	push es
	push fs
	push gs

	mov ax, ss
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

	mov esi, esp

	inc dword [k_reenter]
	cmp dword [k_reenter], 0
	jne .1
	mov eax, 0xFFFFE000
	and esp, eax
	add esp, 0x2000
.1:
	jmp [esi + RETADR - P_STACKBASE]
;--------------------------------------------------------------

extern syscall_handler
_syscall:
	;Save status
	call save

	push esi 
	call syscall_handler
	add esp, 4

	dec dword [k_reenter]

	sub esp, 0x1ffc
	;Restore status
	pop	gs
	pop	fs
	pop	es
	pop	ds
	popad
	add esp, 4
	iretd

global CallUser
;[ebp+C]    esp --> ecx
;[ebp+8]    eip --> edx
CallUser:
	push ebp
	mov ebp, esp
	mov edx, [ebp+0x8]
	mov ecx, [ebp+0xC]

	push ds
	push es
	push fs
	push gs
	xchg esp, ecx

	mov ax, 0x18
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	push ecx        ; save old esp
	push dword 0x30
	push dword edx
	call dword far [ss:esp]
	add esp, 8
	pop esp		; restore old esp
	mov ax, 0x10
	mov ss, ax	; restore old ss
	
	pop gs
	pop fs
	pop es
	pop ds

	mov esp, ebp
	pop ebp
	ret

